﻿/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is BarocStudio.
*
* The Initial Developer of the Original Code is Kevin Ortman.
*
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */

using Irony.Parsing;

namespace BarocLanguage
{
    [Language("BAROC")]
    public class BarocGrammar : Grammar 
    {
        public BarocGrammar()
            : base(false)
        {

            #region Terminals

            // common terminals
            var MEMBER_NAME = new RegexBasedTerminal("MEMBER_NAME", @"[a-zA-Z0-9_]*\w");

            // data type terminals
            var LINE_COMMENT = new CommentTerminal("line-comment", "#", "\r", "\n", "\u2085", "\u2028", "\u2029");

            // symbol terminals
            var COLON = ToTerm(":");
            var SEMI_COLON = ToTerm(";");

            // enumeration terminals
            var ENUM_MEMBER_VALUE = new NumberLiteral("ENUM_MEMBER_VALUE", NumberOptions.IntOnly);
            var ENUM_MEMBER_NAME = new RegexBasedTerminal("ENUM_NAME", @"\[.*\]|\'.*\'|\"".*\""|[a-zA-Z0-9_]*\w");

            //  class terminals
            var CLASS_NAME = new IdentifierTerminal("CLASS_NAME");
            var BASE_CLASS_NAME = new IdentifierTerminal("BASE_CLASS_NAME");
            var SLOT_FACET_VALUE = new RegexBasedTerminal("ENUM_NAME", @"\[.*\]|\'.*\'|\"".*\""|[a-zA-Z0-9_\-\.]*\w");
            var YESNO_VALUE = new RegexBasedTerminal("YESNO_KEY", @"yes|no");
            var REPRESENTATION_VALUE = new RegexBasedTerminal("REPRESENTATION_VALUE", @"date|class|diary");


            // 
            // Non-Terminals
            //
            var root = new NonTerminal("root");
            var barocObject = new NonTerminal("barocObject");
            var barocObjects = new NonTerminal("barocObjects");
            var enumerationMember = new NonTerminal("enumerationMember");
            var enumerationMembers = new NonTerminal("enumerationMembers");
            var classMember = new NonTerminal("classMember");
            var classMembers = new NonTerminal("classMembers");
            var classMemberType = new NonTerminal("classMemberType");
            var typeModifier = new NonTerminal("typeModifier");
            var slotFacet = new NonTerminal("slotFacet");
            var slotFacets = new NonTerminal("slotFacets");
            #endregion 


            // 
            // Rules
            //
            Root = root;
            root.Rule = barocObjects;

            barocObjects.Rule = MakeStarRule(barocObjects, barocObject);
            barocObject.Rule = "ENUMERATION" + ENUM_MEMBER_NAME + enumerationMembers + "END"
                         | "MC_EV_CLASS" + COLON + CLASS_NAME + "DEFINES" + "{" + classMembers + "}" + SEMI_COLON + "END"
                         | "MC_EV_CLASS" + COLON + CLASS_NAME + "ISA" + BASE_CLASS_NAME + "DEFINES" + "{" + classMembers + "}" + SEMI_COLON + "END"
                         | "MC_EV_CLASS" + COLON + CLASS_NAME + "ISA" + BASE_CLASS_NAME + SEMI_COLON + "END"
                         | "MC_DATA_CLASS" + COLON + CLASS_NAME + "DEFINES" + "{" + classMembers + "}" + SEMI_COLON + "END"
                         | "MC_DATA_CLASS" + COLON + CLASS_NAME + "ISA" + BASE_CLASS_NAME + "DEFINES" + "{" + classMembers + "}" + SEMI_COLON + "END"
                         | "MC_DATA_CLASS" + COLON + CLASS_NAME + "ISA" + BASE_CLASS_NAME + SEMI_COLON + "END"
                         | "MC_INTERFACE" + COLON + CLASS_NAME + "DEFINES" + "{" + classMembers + "}" + SEMI_COLON + "END"
                         | "MC_INTERFACE" + COLON + CLASS_NAME + SEMI_COLON + "END"
                         | "RECORD" + CLASS_NAME + "DEFINES" + "{" + classMembers + "}" + "END"
                         | "ROOT" + COLON + CLASS_NAME + SEMI_COLON + "END"
                         | "ROOT" + COLON + CLASS_NAME + "ISA" + BASE_CLASS_NAME + SEMI_COLON + "END"
                         | "MC_PUBLISH_DATA_CLASS" + COLON + CLASS_NAME + "ISA" + BASE_CLASS_NAME + "DEFINES" + "{" + classMembers + "}" + SEMI_COLON + "END"
                         | "MC_PUBLISH_DATA_CLASS" + COLON + CLASS_NAME + "ISA" + BASE_CLASS_NAME + SEMI_COLON + "END"
                         ;

            enumerationMembers.Rule = MakePlusRule(enumerationMembers, enumerationMember);
            enumerationMember.Rule = ENUM_MEMBER_VALUE + ENUM_MEMBER_NAME;

            classMembers.Rule = MakeStarRule(classMembers, classMember);
            classMember.Rule = MEMBER_NAME + COLON + typeModifier + classMemberType + SEMI_COLON
                             | MEMBER_NAME + COLON + slotFacets + SEMI_COLON
                             | MEMBER_NAME + COLON + typeModifier + classMemberType + "," + slotFacets + SEMI_COLON;

            classMemberType.Rule = Empty
                                 | ToTerm("INTEGER")
                                 | ToTerm("STRING")
                                 | ToTerm("REAL")
                                 | ToTerm("STATUS")
                                 | ToTerm("MC_YESNO")
                                 | ToTerm("INT32")
                                 | ToTerm("QUERY") + CLASS_NAME
                                 | CLASS_NAME;

            typeModifier.Rule = Empty | ToTerm("LIST_OF") | ToTerm("ECF");

            slotFacets.Rule = MakePlusRule(slotFacets, ToTerm(","), slotFacet);
            slotFacet.Rule = ToTerm("default") + "=" + SLOT_FACET_VALUE
                           | ToTerm("dup_detect") + "=" + YESNO_VALUE
                           | ToTerm("key") + "=" + YESNO_VALUE
                           | ToTerm("read_only") + "=" + YESNO_VALUE
                           | ToTerm("representation") + "=" + REPRESENTATION_VALUE
                           | ToTerm("parse") + "=" + YESNO_VALUE
                           | ToTerm("hidden") + "=" + YESNO_VALUE
                           ;



            // 
            // Non-Grammar Rules
            //
            NonGrammarTerminals.Add(LINE_COMMENT);

        }


    }
}
